/*
 * Copyright 2009-2010 Nanjing RedOrange ltd (http://www.red-orange.cn)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package redora.client.mvp;

import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import redora.client.Persistable;

import java.util.ArrayList;

/**
 * Invoking one of the findById methods will result in the firing of
 * one ore two FetchEvents. The FetchEvent will contain the requested
 * pojo(s).<br>
 * For example, you run findById(new Long[]{2L, 14L, 44L}, Table), requesting for
 * three objects. The last, id = 44L is already in the cache and will be
 * returned almost immediately with a FetchEvent. You can get this pojo
 * by invoking event.getPojo(14L). The other two pojo's are retrieved from
 * the server. As soon as the server has responded with the remaining pojo's
 * It will fire the second FetchEvent.<br>
 * How do you know your object is in the events payload?<br>
 * By using the hasMe, union and getPojo methods:
 * <code>
 * if (event.hasMe(Example.class, new Long[]{2L, 14L, 44L})) {
       for (Long id : event.union(new Long[]{2L, 14L, 44L})) {
           log("Fetched: " + event.getPojo(id));
       }
   }
 * </code>
 *
 * @see ServiceBase#findById(Long, redora.client.Persistable.Scope)
 * @see ServiceBase#findById(Long[], redora.client.Persistable.Scope)
 */
public class FetchEvent extends GwtEvent<FetchEvent.Handler> {
    public static Type<FetchEvent.Handler> TYPE = new Type<FetchEvent.Handler>();

    public interface Handler extends EventHandler {
        void onSuccess(final FetchEvent event);
    }

    public boolean hasMe(Class<? extends Persistable> cls, Long id) {
        return this.cls.equals(cls) && getPojo(id) != null;
    }

    public boolean hasMe(Class<? extends Persistable> cls, Long[] ids) {
        return this.cls.equals(cls) && !union(ids).isEmpty();
    }

    public Persistable getPojo(Long id) {
        for (Persistable p : results) {
            if (p.getId().equals(id))
                return p;
        }
        return null;
    }

    public final Persistable[] results;
    public final Class<? extends Persistable> cls;

    public FetchEvent(final Class<? extends Persistable> cls, final Persistable[] results) {
        this.cls = cls;
        this.results = results;
    }

    @Override
    public Type<FetchEvent.Handler> getAssociatedType() {
        return TYPE;
    }

    @Override
    protected void dispatch(FetchEvent.Handler handler) {
        handler.onSuccess(this);
    }

    public ArrayList<Long> union(Long[] ids) {
        ArrayList<Long> retVal = new ArrayList<Long>();
        if (ids == null)
            return retVal;

        for (Persistable p : results) {
            for (Long id : ids) {
                if (p.getId().equals(id)) {
                    retVal.add(id);
                    break;
                }
            }
        }

        return retVal;
    }

}
